/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_ENCODER)

#include "umc_avs_enc_pic.h"
#include "umc_avs_enc_slice.h"

namespace UMC
{

enum
{
    PLANE_ALIGN_VALUE           = 64
};

AVSEncFrame::AVSEncFrame(void)
{
    m_pvSrcVideoPlane = (void *) 0;
    m_srcBufSize = 0;

} // AVSEncFrame::AVSEncFrame(void)

AVSEncFrame::~AVSEncFrame(void)
{
    Close();

} // AVSEncFrame::~AVSEncFrame(void)

void AVSEncFrame::Close(void)
{
    // deallocate buffer
    if (m_pvSrcVideoPlane)
    {
        ippsFree(m_pvSrcVideoPlane);
    }

    m_pvSrcVideoPlane = (void *) 0;
    m_srcBufSize = 0;

} // void AVSEncFrame::Close(void)

Status AVSEncFrame::Init(void)
{
    Status umcRes;

    //
    // do not close the object before initialization,
    // because memory allocating operations are very expensive.
    //

    // call the parent's method
    umcRes = AVSFrame::Init();
    if (UMC_OK != umcRes)
        return umcRes;

    if (m_srcBufSize < m_bufSize)
    {
        // deallocate reference plane buffer
        if (m_pvSrcVideoPlane)
        {
            ippsFree(m_pvSrcVideoPlane);

            m_pvSrcVideoPlane = (void *) 0;
            m_srcBufSize = 0;
        }

        m_pvSrcVideoPlane = ippsMalloc_8u((int) m_bufSize);
        if (NULL == m_pvSrcVideoPlane)
            return UMC_ERR_ALLOC;
        m_srcBufSize = m_bufSize;
    }

    // set reference plane pointers
    m_pSrcPlanes8u[0] = (Ipp8u *) m_pvSrcVideoPlane;
    m_pSrcPlanes8u[1] = m_pSrcPlanes8u[0] + m_dimLumaAllocated.width * m_dimLumaAllocated.height;
    m_pSrcPlanes8u[2] = m_pSrcPlanes8u[1] + m_dimLumaAllocated.width / 2;

    m_Fields[0].m_pSrcPlanes8u[0] = m_pSrcPlanes8u[0];
    m_Fields[0].m_pSrcPlanes8u[1] = m_pSrcPlanes8u[1];
    m_Fields[0].m_pSrcPlanes8u[2] = m_pSrcPlanes8u[2];

    m_Fields[1].m_pSrcPlanes8u[0] = m_pSrcPlanes8u[0] + m_iPitch;
    m_Fields[1].m_pSrcPlanes8u[1] = m_pSrcPlanes8u[1] + m_iPitch;
    m_Fields[1].m_pSrcPlanes8u[2] = m_pSrcPlanes8u[2] + m_iPitch;

    return UMC_OK;

} // Status AVSEncFrame::Init(void)

void AVSEncFrame::AssignVideoPlanes(AVSSlice *pSlice)
{
    // call the parent's method
    AVSFrame::AssignVideoPlanes(pSlice);

    // set the reference planes
    if (AVS_FRAME == m_picStructure)
    {
        const Ipp8u *(pPlanes8u[3]);

        // advance video planes
        GetPlanesPointers(pPlanes8u,
                          m_pSrcPlanes8u,
                          m_iPitch,
                          pSlice->m_recCtx.MbY,
                          m_colorFormat);

        memcpy(((AVSEncSlice *) pSlice)->m_disCtx.m_pSrcPlanes8u,
               pPlanes8u,
               sizeof(pPlanes8u));
        ((AVSEncSlice *) pSlice)->m_disCtx.m_iPitch = m_iPitch;
        memcpy(((AVSEncSlice *) pSlice)->m_meCtx.m_pSrcPlanes8u,
               pPlanes8u,
               sizeof(pPlanes8u));
        ((AVSEncSlice *) pSlice)->m_meCtx.m_iPitch = m_iPitch;

    }
    else
    {
        const Ipp8u *(pPlanes8u[3]);
        Ipp32u fieldNum = pSlice->m_SlcHeader.isSecondField;

        // advance video planes
        GetPlanesPointers(pPlanes8u,
                          m_Fields[fieldNum].m_pSrcPlanes8u,
                          m_Fields[fieldNum].m_iPitch,
                          pSlice->m_recCtx.MbY,
                          m_colorFormat);

        memcpy(((AVSEncSlice *) pSlice)->m_disCtx.m_pSrcPlanes8u,
               pPlanes8u,
               sizeof(pPlanes8u));
        ((AVSEncSlice *) pSlice)->m_disCtx.m_iPitch = m_Fields[fieldNum].m_iPitch;

        memcpy(((AVSEncSlice *) pSlice)->m_meCtx.m_pSrcPlanes8u,
               pPlanes8u,
               sizeof(pPlanes8u));
        ((AVSEncSlice *) pSlice)->m_meCtx.m_iPitch = m_Fields[fieldNum].m_iPitch;

    }


} // void AVSEncFrame::AssignVideoPlanes(AVSSlice *pSlice)

Status AVSEncFrame::SetSlices(void)
{
    // call the parent's method
    // set params for m_disCtx, m_encCtx, m_recCtx
    AVSFrame::SetSlices();

    // set params for m_meCtx
    AVSListElement<AVSSlice> *pSlice;
    pSlice = m_Slices.GetHead();
    pSlice->m_meCtx.m_pMBInfo = pSlice->m_decCtx.m_pMBInfo;

    return UMC_OK;
} // Status AVSEncFrame::SetSlices(void)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_ENCODER)
